package com.neusoft.databus.policy.event.impl;

import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.google.common.eventbus.AsyncEventBus;
import com.neusoft.bizcore.common.cache.CacheService;
import com.neusoft.databus.common.bean.ResourceBean;
import com.neusoft.databus.policy.config.DatabusPolicyProperties;
import com.neusoft.databus.policy.enums.EventStatus;
import com.neusoft.databus.policy.event.PolicyEventHandler;
import com.neusoft.databus.policy.model.Event;
import com.neusoft.databus.policy.model.EventAttribute;
import com.neusoft.databus.policy.model.Policy;
import com.neusoft.databus.policy.utils.PolicyUtil;

import lombok.extern.slf4j.Slf4j;

/**
 * 通信中断事件处理类
 *
 * @author naxiang
 */
@Slf4j
@Component("suspendPolicyEventHandler")
public class SuspendPolicyEventHandlerImpl extends PolicyEventHandler {
    @Autowired
    private DatabusPolicyProperties policyProperties;

    @Autowired
    private CacheService cacheService;

    @Autowired
    private AsyncEventBus policyEventBus;

    private volatile boolean ENABLE_RES_INTERRUPT_IGNORE_INTERVAL = false;
    private volatile long RES_INTERRUPT_IGNORE_INTERVAL = 0L;
    //    private volatile long RES_INTERRUPT_IGNORE_FAR_AFTERINTERVAL = Long.MAX_VALUE;

    private void handleResInterruptIgnoreInterval() {
        if (this.RES_INTERRUPT_IGNORE_INTERVAL == 0L) {
            if (this.policyProperties.getInterruptIgnoreInterval() > 0) {
                SuspendPolicyEventHandlerImpl.log.debug("加载无视通信中断时间间隔{}",
                        this.policyProperties.getInterruptIgnoreInterval());
                this.ENABLE_RES_INTERRUPT_IGNORE_INTERVAL = true;
                try {
                    this.RES_INTERRUPT_IGNORE_INTERVAL = this.policyProperties.getInterruptIgnoreInterval();
                } catch (final Exception e) {
                    SuspendPolicyEventHandlerImpl.log.error("首次通信中断到当次通讯中断时间间隔获取失败:{}", e);
                }
                //                try {
                //                    if (this.policyProperties.getInterruptIgnoreFarAferinterval() > 0) {
                //                        this.RES_INTERRUPT_IGNORE_FAR_AFTERINTERVAL =
                //                                this.policyProperties.getInterruptIgnoreFarAferinterval();
                //                    }
                //                } catch (final Exception e) {
                //                    SuspendPolicyEventHandlerImpl.log.error("首次通信中断到当次通讯中断时间间隔获取失败:{}", e);
                //                }
            } else {
                SuspendPolicyEventHandlerImpl.log.debug("无条件触发中断告警!");
            }
        }
    }

    @Override
    public void trigger(ResourceBean resourceBean, Date time, Policy policy,
            final List<Integer> expressionTrueSquence) {
        final String resourceCode = resourceBean.getCode();
        final String key = PolicyUtil.getEventKey(resourceCode, policy.getCode());
        Event event = null;
        try {
            event = this.getEvent(policy, resourceCode);
            final EventAttribute eventAttibute = event.getEventAttribute();
            eventAttibute.setLastTime(time);
            eventAttibute.setContent(this.eventContent(resourceCode, policy.getContentTemplate()));
            //event.setSort(EventSort.SYSTEM);// 策略告警
            event.setStatus(EventStatus.UNFIXED);
            synchronized (this.getLockInstance(resourceCode)) {
                this.handleResInterruptIgnoreInterval();
                // 设置通讯中断无视时间间隔，则进行通信中断是否上报判断
                if (this.ENABLE_RES_INTERRUPT_IGNORE_INTERVAL) {
                    final String keyTime = PolicyUtil.getSuspendTimeKey(resourceCode, policy);
                    final String keyCount = PolicyUtil.getSuspendCountKey(resourceCode, policy);
                    this.intevalInterruptCountCache(PolicyEventHandler.cacheName, keyCount);
                    if (!this.cacheService.isInCache(PolicyEventHandler.cacheName, keyTime)) {
                        // 首次通信中断发生，只记录发生时间。等待下一周期判定设备状态
                        this.cacheService.put(PolicyEventHandler.cacheName, keyTime, time.getTime());
                        SuspendPolicyEventHandlerImpl.log.debug("resourceCode:{}首次通信中断告警，不处理，本次中断发生时间为{}", resourceCode,
                                time.getTime());
                        return;
                    } else {
                        final Long preAlertTimestamp =
                                (Long) this.cacheService.get(PolicyEventHandler.cacheName, keyTime);
                        final long minus = time.getTime() - preAlertTimestamp;
                        if (minus < this.RES_INTERRUPT_IGNORE_INTERVAL) {
                            SuspendPolicyEventHandlerImpl.log.debug(
                                    "resourceCode:{} 在无视通信中断时间间隔内，第{}次中断告警，不处理。首次中断发生时间为{}，本次中断发生时间为{} 相差{}",
                                    resourceCode, this.cacheService.get(PolicyEventHandler.cacheName, keyCount),
                                    preAlertTimestamp,
                                    time.getTime(), minus);
                            return;
                        }
                        //                        if (minus > this.RES_INTERRUPT_IGNORE_FAR_AFTERINTERVAL) {
                        //                            this.cacheService.put(PolicyEventHandler.cacheName, keyTime, time.getTime());
                        //                            SuspendPolicyEventHandlerImpl.log.debug(
                        //                                    "resourceCode:{} 本次通信中断发生时间距离上次中断发生时间超过忽视时间，默认为首次中断告警，不处理。上次中断发生时间为{}，本次中断发生时间为{} 相差{}",
                        //                                    resourceCode, preAlertTimestamp, time, minus);
                        //                            return;
                        //                        }
                        SuspendPolicyEventHandlerImpl.log.debug("resourceCode:{}上次中断发生时间为{}，本次中断发生时间为{} 相差{}",
                                resourceCode, preAlertTimestamp,
                                time.getTime(), minus);
                    }
                }
                if (!this.cacheService.isInCache(PolicyEventHandler.cacheName,
                        key)) {
                    this.cacheService.put(PolicyEventHandler.cacheName,
                            key, event.getCode());
                } else {
                    event.setCode(String.valueOf(this.cacheService.get(
                            PolicyEventHandler.cacheName, key)));
                }
            }
            this.policyEventBus.post(event);
        } catch (final Exception e) {
            SuspendPolicyEventHandlerImpl.log.error("通信中断告警事件,策略code:{},资源code:{},产生异常{}", policy.getCode(),
                    resourceCode, e);
        } finally {
            // 置空大对象,以免内存增长过快
            time = null;
            event = null;
            resourceBean = null;
            policy = null;
        }

    }

    @Override
    public void fixed(ResourceBean resourceBean, Date time, Policy policy) {
        final String resourceCode = resourceBean.getCode();
        final String key = PolicyUtil.getEventKey(resourceCode, policy.getCode());
        Event event = this.getEvent(policy, resourceCode);
        event.setStatus(EventStatus.FIXED);
        try {
            synchronized (this.getLockInstance(resourceCode)) {
                // 如果是中断恢复的话，清除对应的触发时间
                final String keyTime = PolicyUtil.getSuspendTimeKey(resourceCode, policy);
                this.cacheService.remove(PolicyEventHandler.cacheName, keyTime);
                final String keyCount = PolicyUtil.getSuspendCountKey(resourceCode, policy);
                this.cacheService.remove(PolicyEventHandler.cacheName, keyCount);
                if (!this.cacheService.isInCache(PolicyEventHandler.cacheName, key)) {
                    SuspendPolicyEventHandlerImpl.log.debug("缓存中未查询到设备通讯中断的告警事件{}", key);
                    return;
                }
                final String code = (String) this.cacheService.get(PolicyEventHandler.cacheName, key);
                event.setCode(code);
                event.setFixTime(time);
                this.policyEventBus.post(event);
            }
        } catch (final Exception e) {
            SuspendPolicyEventHandlerImpl.log.error("通讯中断告警解除事件,策略code:{},资源code:{},产生异常{}", policy.getCode(),
                    resourceCode, e);
        } finally {
            // 置空大对象,以免内存增长过快
            time = null;
            event = null;
            resourceBean = null;
            policy = null;
        }
    }

    /**
     * 缓存通讯中断次数
     *
     * @param cacheName
     * @param key
     */
    private void intevalInterruptCountCache(final String cacheName, final String key) {
        if (this.cacheService.isInCache(cacheName, key)) {
            this.cacheService.put(cacheName, key,
                    (Integer.valueOf(String.valueOf(this.cacheService.get(cacheName, key))) + 1));
        } else {
            this.cacheService.put(cacheName, key, 1);
        }
    }
}
